package com.wy.sentinel;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

/**
 * Sentinel规则默认是保存在内存中的,持久化可以保存在本地文件,也可以利用nacos保存
 * 
 * 1.利用本地文件持久化规则,实现接口
 * 
 * 2.在resources下创建配置目录META-INF/services,然后添加文件com.alibaba.csp.sentinel.init.InitFunc,
 * 在文件中添加配置类的全路径com.wy.sentinel.MySentinel03
 * 
 * @author 飞花梦影
 * @date 2022-02-26 17:10:57
 * @git {@link https://github.com/dreamFlyingFlower}
 */
public class MySentinel03 implements InitFunc {

	private Converter<String, List<FlowRule>> flowRuleListParser =
			source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
			});

	private Converter<String, List<DegradeRule>> degradeRuleListParser =
			source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
			});

	private Converter<String, List<SystemRule>> systemRuleListParser =
			source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {
			});

	private Converter<String, List<AuthorityRule>> authorityRuleListParser =
			source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {
			});

	private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser =
			source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
			});

	@Value("spring.application:name")
	private String appcationName;

	@Override
	public void init() throws Exception {
		String ruleDir = System.getProperty("user.home") + "/sentinelrules/" + appcationName;
		String flowRulePath = ruleDir + "/flow-rule.json";
		String degradeRulePath = ruleDir + "/degrade-rule.json";
		String systemRulePath = ruleDir + "/system-rule.json";
		String authorityRulePath = ruleDir + "/authority-rule.json";
		String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
		this.mkdirIfNotExits(ruleDir);
		this.createFileIfNotExits(flowRulePath);
		this.createFileIfNotExits(degradeRulePath);
		this.createFileIfNotExits(systemRulePath);
		this.createFileIfNotExits(authorityRulePath);
		this.createFileIfNotExits(paramFlowRulePath);
		// 流控规则
		ReadableDataSource<String, List<FlowRule>> flowRuleRDS =
				new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
		FlowRuleManager.register2Property(flowRuleRDS.getProperty());
		WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath, this::encodeJson);
		WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
		// 降级规则
		ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS =
				new FileRefreshableDataSource<>(degradeRulePath, degradeRuleListParser);
		DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
		WritableDataSource<List<DegradeRule>> degradeRuleWDS =
				new FileWritableDataSource<>(degradeRulePath, this::encodeJson);
		WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
		// 系统规则
		ReadableDataSource<String, List<SystemRule>> systemRuleRDS =
				new FileRefreshableDataSource<>(systemRulePath, systemRuleListParser);
		SystemRuleManager.register2Property(systemRuleRDS.getProperty());
		WritableDataSource<List<SystemRule>> systemRuleWDS =
				new FileWritableDataSource<>(systemRulePath, this::encodeJson);
		WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
		// 授权规则
		ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS =
				new FileRefreshableDataSource<>(authorityRulePath, authorityRuleListParser);
		AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
		WritableDataSource<List<AuthorityRule>> authorityRuleWDS =
				new FileWritableDataSource<>(authorityRulePath, this::encodeJson);
		WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
		// 热点参数规则
		ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS =
				new FileRefreshableDataSource<>(paramFlowRulePath, paramFlowRuleListParser);
		ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
		WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS =
				new FileWritableDataSource<>(paramFlowRulePath, this::encodeJson);
		ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
	}

	private void mkdirIfNotExits(String filePath) throws IOException {
		File file = new File(filePath);
		if (!file.exists()) {
			file.mkdirs();
		}
	}

	private void createFileIfNotExits(String filePath) throws IOException {
		File file = new File(filePath);
		if (!file.exists()) {
			file.createNewFile();
		}
	}

	private <T> String encodeJson(T t) {
		return JSON.toJSONString(t);
	}
}